package mod

import (
	"fmt"
	"service/conf"
	"service/ctrl"
	"time"
	"unicode/utf8"

	"gitee.com/cloudapex/ulern/util"

	"gitee.com/cloudapex/ulern/htp"
	"gitee.com/cloudapex/ulern/rds"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-09
Description: 公共数据
*******************************************************************************/

/*------------------------------------------------------------------------------
======================================常量=======================================
------------------------------------------------------------------------------*/

// 常量定义
const (
	MH_AUTH = "mh_auth" // 认证中间件名称

	TMP_CLS_DURATION = 24 * time.Hour // 临时开课有效时长

	FRAME_DIGIT_UNIT  = uint64(10000)             // 组织架构每级位数
	FRAME_DIGIT_TOTAL = uint64(10000000000000000) // 组织架构最大位数
	FRAME_LEVEL_MAX   = 4                         // 最大组织架构层级
)

// 管理GRPC服务的连接命名
const (
	GCONN_PERMIS    = "permis"   // 权限服务连接器 9876
	GCONN_HR        = "hr"       // 人事服务连接器 9003
	GCONN_HR_CACHE  = "hrCache"  // 人事缓存服务连接器 9008
	GCONN_KB_PRO    = "kbPro"    // 知识库(项目) 9010
	GCONN_KB_SYS    = "kbSys"    // 知识库(系统) 9011
	GCONN_NOTIFY    = "notify"   // 公司公告 9012
	GCONN_CRM_BASE  = "crmBase"  // crm数据 9016
	GCONN_CRM_ORDER = "crmOrder" // crm订单 9015
)

/*------------------------------------------------------------------------------
======================================类型=======================================
------------------------------------------------------------------------------*/

// => 缓存库连接类型
type ERDB int //
const (
	ERDB_Permt ERDB = iota // 权限缓存库
	ERDB_Max
)

func RDB(e ERDB) *rds.Pool {
	return ctrl.RDB.Use(int(e))
}

// => 时间字段类型
type ETimeField = int //
const (
	ETF_Unix   ETimeField = iota // unix
	ETF_Format                   // string_format
)

// => 记录状态类型
type EStateField = int //
const (
	EState_Enable EStateField = iota + 1 // 有效
	EState_Unable                        // 无效
)

// => 订单类型
type EOrderType int //
const (
	EOrderT_NetClass EOrderType = iota + 1 // 网课
	EOrderT_Diploma                        // 学历
	EOrderT_Enroll                         // 协助报名
	EOrderT_Credent                        // 证书
	EOrderT_Other                          // 其他
)

func (e EOrderType) String() string {
	switch e {
	case EOrderT_NetClass:
		return "网课"
	case EOrderT_Diploma:
		return "学历"
	case EOrderT_Enroll:
		return "协助报名"
	case EOrderT_Credent:
		return "证书"
	case EOrderT_Other:
		return "其他"
	}
	return fmt.Sprintf("EOrderT_unknow(%d)", e)
}

// 订单类型列表
var OrderTypes = []DictItem{
	{int(EOrderT_NetClass), EOrderT_NetClass.String()},
	{int(EOrderT_Diploma), EOrderT_Diploma.String()},
	{int(EOrderT_Enroll), EOrderT_Enroll.String()},
	{int(EOrderT_Credent), EOrderT_Credent.String()},
	{int(EOrderT_Other), EOrderT_Other.String()},
}

// => 订单支付类型
type EPayType int //
const (
	EPayT_Full    EPayType = iota + 1 // 全款
	EPayT_Tail                        // 尾款
	EPayT_Handsel                     // 定金
)

func (e EPayType) String() string {
	switch e {
	case EPayT_Full:
		return "全款"
	case EPayT_Tail:
		return "尾款"
	case EPayT_Handsel:
		return "定金"
	}
	return fmt.Sprintf("EPayT_unknow(%d)", e)
}

var PayTypes = []DictItem{ // 列表
	{int(EPayT_Full), EPayT_Full.String()},
	{int(EPayT_Tail), EPayT_Tail.String()},
	{int(EPayT_Handsel), EPayT_Handsel.String()},
}

// => 订单状态枚举
type EOrderState int //
const (
	EOrderS_NoPay      EOrderState = iota + 1 // 未支付 - 未审核
	EOrderS_Payed                             // 已支付 - 未分配 | 已审核(已支付,已分配)
	EOrderS_Assign                            // 已分配
	EOrderS_Reject                            // 已驳回
	EOrderS_HandCancel                        // 手动取消 (取消)
	EOrderS_AutoCancel                        // 自动取消 (取消)
)

func (e EOrderState) String() string {
	switch e {
	case EOrderS_NoPay:
		return "未支付"
	case EOrderS_Payed:
		return "已支付"
	case EOrderS_Assign:
		return "已分配"
	case EOrderS_Reject:
		return "已驳回"
	case EOrderS_HandCancel:
		return "手动取消"
	case EOrderS_AutoCancel:
		return "自动取消"
	}
	return fmt.Sprintf("EOrderS_unknow(%d)", e)
}

// => 支付方式
type EPayWay int //
const (
	EPayW_WX    EPayWay = iota + 1 // 微信
	EPayW_ZFB                      // 支付宝
	EPayW_Other                    // 其他
	EPayW_JH                       // 聚合
	EPayW_SB                       // 扫呗
	EPayW_LT                       // 通联
)

func (e EPayWay) string() string {
	switch e {
	case EPayW_WX:
		return "微信"
	case EPayW_ZFB:
		return "支付宝"
	case EPayW_Other:
		return "其他"
	case EPayW_JH:
		return "聚合"
	case EPayW_SB:
		return "扫呗"
	case EPayW_LT:
		return "通联"
	}
	return ""
}
func (e EPayWay) String() string {
	if s := e.string(); s == "" {
		return s
	}
	return fmt.Sprintf("EPayW_unknow(%d)", e)
}
func (e EPayWay) BString() string {
	return e.string()
}

var PayWays = []DictItem{
	{int(EPayW_WX), EPayW_WX.String()},
	{int(EPayW_ZFB), EPayW_ZFB.String()},
	{int(EPayW_Other), EPayW_Other.String()},
	{int(EPayW_JH), EPayW_JH.String()},
	{int(EPayW_SB), EPayW_SB.String()},
	{int(EPayW_LT), EPayW_LT.String()},
}

// => 升班未升班
type EUpClass int //
const (
	EUpCls_Not EPayWay = iota + 1 // 未升班
	EUpCls_Yes                    // 已升班
)

// => 订单操作日志类型
// 分配,退费,换课,开课
type EOrderLog int

const (
	EOrderL_Assign EPayWay = iota + 1 // 分配(班主任)
	EOrderL_Refund                    // 退费
	EOrderL_ChaCls                    // 换课
	EOrderL_OpnCls                    // 开课
)

// => 审核方式
type ECheckWay int //
const (
	ECheckW_Auto ECheckWay = iota + 1 // 手动
	ECheckW_Hand                      // 自动
)

type EEducation int //
const (
	EEduct_Big = iota + 1 // 大专
	EEduct_Mid            // 中专
	EEduct_Ben            // 本科
)

var Educations = []DictItem{
	{int(EEduct_Big), "大专"},
	{int(EEduct_Mid), "中专"},
	{int(EEduct_Ben), "本科"},
}

func EducationName(typ int) string {
	for _, it := range Educations {
		if it.Id == typ {
			return it.Val
		}
	}
	return ""
}

//自动分配方式操作人
var AutoAssignId int64 = 1

/*------------------------------------------------------------------------------
======================================结构=======================================
------------------------------------------------------------------------------*/

// ----- CustomClaims
func init() {
	ctrl.Svr.RegistMiddler(func(e *gin.Engine) { htp.InitJwtAuth(MH_AUTH, (*CustomClaims)(nil), conf.Main.Listn().SvrSignKey) })
}

// 载荷，可以加一些自己需要的信息
type CustomClaims struct {
	CId    int64    // 公司Id
	UId    int64    // 用户Id
	PId    int64    // 项目ID [暂时留着]
	HId    int64    // 员工ID
	WorkId int64    // 工号ID [暂时留着]
	ShowId []uint64 // 可见范围(组织架构)ID
	RoleId int64    // 角色ID(角色大类)
	Name   string   // 姓名(昵称)
	Phone  string   // 用户手机号
	jwt.StandardClaims
}                                                              //
func (c *CustomClaims) TheUID() int64                          { return c.UId }
func (c *CustomClaims) TheStandardClaims() *jwt.StandardClaims { return &c.StandardClaims }

func CurrUser(c *gin.Context) *CustomClaims {
	return c.MustGet("claims").(*CustomClaims)
}

// ----- SortFinder
type SortFinder struct {
	Order int `form:"order" json:"order" binding:"omitempty"` // 排序字段(根据后端定义的1,2..数字含义排列,当数字不匹配时,数据端按默认排序字段处理)
	Orule int `form:"orule" json:"orule" binding:"omitempty"` // 0:倒序; 1:正序; (数据端为: 1:倒序,2:升序)
}

// ----- PageFinder
type PageFinder struct {
	Pnum int   `form:"pnum" json:"pnum" binding:"required,min=1,max=100"` // 单页数量
	Page int   `form:"page" json:"page" binding:"required"`               // 页码
	Bgn  int64 `form:"bgn" json:"bgn" binding:"omitempty"`                // 开始时间(int)
	End  int64 `form:"end" json:"end" binding:"omitempty"`                // 结束时间(int)(二选一)
	//BgnS  util.TJsTime `form:"bgnS" json:"bgnS" binding:"omitempty"`              // 开始时间(string)
	//EndS  util.TJsTime `form:"endS" json:"endS" binding:"omitempty"`              // 结束时间(string)(二选一)
}

// 字典结构
type DictItem struct {
	Id  int    `json:"id"`
	Val string `json:"val"`
}

/*------------------------------------------------------------------------------
======================================方法=======================================
------------------------------------------------------------------------------*/

// 组合节点路径
func NodePath(parentPath string, parentId int64) string {
	if parentId == 0 {
		return "0"
	}
	return fmt.Sprintf("%s/%d", parentPath, parentId)
}

/**
删除字符串中最后一个字符
*/
func TrimLastChar(s string) string {
	r, size := utf8.DecodeLastRuneInString(s)
	if r == utf8.RuneError && (size == 0 || size == 1) {
		size = 0
	}
	return s[:len(s)-size]
}

/**
时间戳转换成年月日时分秒
*/
func GetTimestr(ntime int64) (strTime string) {
	if ntime > 0 {
		strTime = util.TimeFormat(time.Unix(ntime, 0))
		return
	}
	return strTime
}

/*
 * 描述: 计算showId的右区间及当前层级
 * 入参: id 某showId
 * 出参: 右区间和当前层级
 * 层级: 0:中心 1:事业 2:军团 3:部 4:组
 *********************************************************************/
func Section(id uint64) (uint64, int) {
	m := FRAME_DIGIT_UNIT
	for i := FRAME_LEVEL_MAX; i > 0; i-- {
		if id%m == 0 {
			m *= FRAME_DIGIT_UNIT
			continue
		}
		return id + m/FRAME_DIGIT_UNIT, i
	}
	return 0, 0
}

func SectionNew(id uint64) uint64 {
	var val uint64 = 1
	for {
		val *= 10000
		if id%val > 0 {

			fmt.Println("最后一次循环：")
			fmt.Println(val)

			return id + val/10000
		} else if 10000000000000000 == val {
			return id + val
		}
	}
	return 0
}

func IsArmy(ids []uint64) bool {
	min := Min(ids)
	_, level := Section(min)
	if level == 2 {
		return true
	}
	return false
}

func Min(ids []uint64) uint64 {
	var min uint64
	for k, val := range ids {
		if k == 0 {
			min = val
		} else {
			if val <= min {
				min = val
			}
		}
	}
	return min
}

/*
 * 描述: 计算showIds中哪个层级最大
 * 入参: showIds
 * 出参: 层级最大的那个showId(相等情况下取第一个)
 *********************************************************************/
func SectionMaxLv(ids []uint64) uint64 {
	id_, lv_ := uint64(0), 0
	for _, id := range ids {
		_, lv := Section(id)
		if lv > lv_ {
			id_, lv_ = id, lv
		}
	}
	return id_
}

/*
 * 描述: 计算showId分离后的各个showId组成部分
 * 入参: showId,all(all=true 时 会把无效的层级用0填充,否则只返回有效的ids)
 * 出参: 返回分离后的showIds
 * 层级: 0:中心 1:事业 2:军团 3:部 4:组  -> 同时也是return切片的下标
 *********************************************************************/
func SectionDepartIds(id uint64, all bool) []uint64 {
	ids := []uint64{}
	m, last := FRAME_DIGIT_TOTAL, uint64(0)
	for i := 0; i <= FRAME_LEVEL_MAX; i++ {
		n := id / m * m
		if n == last {
			break
		}
		ids = append(ids, n)
		last, m = n, m/FRAME_DIGIT_UNIT
	}
	if all {
		for i, n := 0, len(ids); i <= FRAME_LEVEL_MAX-n; i++ {
			ids = append(ids, 0)
		}
	}
	return ids
}

/*
 * 描述: 计算showId的特定层级的showId
 * 入参: showId,层级( 0:中心 1:事业 2:军团 3:部 4:组 )
 * 出参: 返回特定层级的showId
 *********************************************************************/
func SectionTheLvId(id uint64, lv int) uint64 {
	m := FRAME_DIGIT_TOTAL
	for i := 1; i <= lv && i <= FRAME_LEVEL_MAX; i++ {
		m /= FRAME_DIGIT_UNIT
	}
	return id / m * m
}

/*
 * 描述: 计算showIds去重后的showids
 * 入参: showIds
 * 出参: 返回经过去除重叠后的showIds
 *********************************************************************/
func SectionDecovered(ids []uint64) []uint64 {
	ids_ := []uint64{}
	mapIdRanges := map[uint64][]uint64{}
	for _, id := range ids {
		right, _ := Section(id)
		contain := false
		for _, v := range mapIdRanges {
			if id >= v[0] && right <= v[1] {
				contain = true
				break
			}
		}
		if !contain {
			mapIdRanges[id] = append(mapIdRanges[id], id, right)
		}
	}
	for k, _ := range mapIdRanges {
		ids_ = append(ids_, k)
	}
	return ids_
}
